<template>
    <div class="code-demo">
        <section class="demo">
            <component :is="asyncComponent" />
        </section>
        <section ref="codeContent" :class="['code', showCode && 'show-code']">
            <CodeContent
                ref="code"
                size="large"
                :code="encodeStr"
                @copyCode="copyCode"
            />
        </section>
        <section class="operate-demo-block">
            <span v-show="encodeStr" @click="toggleCode">{{
                showCode ? "隐藏代码" : "显示代码"
            }}</span>
            <span @click="copyCode">复制代码</span>
            <span @click="onlineDebug">在线调试</span>
        </section>
    </div>
</template>

<script setup>
import { codeToHtml } from "shiki";
import {
    defineAsyncComponent,
    markRaw,
    shallowRef,
    ref,
    onMounted,
    watch,
} from "vue";
import { SyncMarkdownCode } from "@design/common";

// 导入所有 demo vue 代码
const globalDemo = import.meta.glob("@docs/example/**/*.vue");

const code = ref(null);
const encodeStr = ref();
const showCode = ref(false);
const codeContent = ref(null);
const asyncComponent = shallowRef();
const props = defineProps({
    code: {
        type: String,
        default: () => "",
    },
    source: {
        type: String,
        default: () => "",
    },
});

const renderComponent = async () => {
    let component = null;
    if (props.source) {
        for (const path in globalDemo) {
            if (path.includes(props.source)) {
                component = globalDemo[path];
                break;
            }
        }
    }

    const timer = setTimeout(() => {
        clearTimeout(timer);
        asyncComponent.value = defineAsyncComponent(
            component
                ? markRaw(component)
                : () => import("@/component/NotFound.vue"),
        );
    }, 50);
};

const copyCode = () => {
    code.value.copyCode();
};

const toggleCode = () => {
    showCode.value = !showCode.value;

    if (!showCode.value) {
        codeContent.value.style.height = 0;
    } else {
        codeContent.value.style.height = "auto";
        const { height } = codeContent.value.getBoundingClientRect();
        codeContent.value.style.height = 0;
        codeContent.value.getBoundingClientRect();
        codeContent.value.style.height = height + "px";
    }
};

const onlineDebug = () => {};

onMounted(() => {
    renderComponent();
    if (process.env.NODE_ENV === "production") encodeStr.value = props.code;

    SyncMarkdownCode(props.source, ({ sourceCode }) => {
        encodeStr.value = sourceCode;
    });
});

// props code 与 encode 代理，兼容 props 更改
watch(props, ({ code }) => (encodeStr.value = code));
</script>

<style lang="less" scoped>
.code-demo {
    max-width: 98%;
    margin: 0 auto;
    border-radius: 6px;
    border: 1px solid @border-color;

    .demo {
        padding: @max-space;
        border-bottom: 1px solid @border-color;
    }

    .code {
        height: 0;
        overflow: hidden;
        position: relative;
        transition: all 0.3s ease-out;
    }

    .operate-demo-block {
        width: 100%;
        line-height: 50px;
        display: flex;
        justify-content: space-between;

        span {
            flex: 1;
            cursor: pointer;
            text-align: center;
            font-size: @small-font-size;
            color: @primary-font-description-color;
        }
    }
}
</style>
